package org.webscale.json.client;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;

import org.apache.log4j.Logger;
import org.webscale.ApplicationException;
import org.webscale.json.JsonStatusBatchResponse;
import org.webscale.json.JsonStatusResponse;
import org.webscale.json.client.JsonClient.ResultNotifier;


public class JsonMultiThreadedExecutor {
	private static final Logger log = Logger
			.getLogger(JsonMultiThreadedExecutor.class);
	
	private int poolSize = 5;
	private  ExecutorService pool;
	public JsonMultiThreadedExecutor(){
			super();
	}
	
	public void init(){
		 pool = Executors.newFixedThreadPool(getMaxPoolSize()); //TODO: figure out if you want to use cached pool or fixed pool
		 log.info("Init for SQS Service called");
	}
	
	
	public Job createNewJob(){
		return new Job();
	}
	
	private Future processClientRequest(JsonClient client ) {
		Future futureTask = null;
		if(!pool.isShutdown()){
			log.debug("processing new client request " +client.getJsonRequestId());
			futureTask = pool.submit(client);
			//pool.execute(client);
		}else{
		   log.warn("The Pool is shutdown and hence will not run this task " + client.getJsonRequestId());	
		}
		return futureTask;
    }
	
	
	
	public int getPoolSize() {
		return poolSize;
	}

	public void setPoolSize(int poolSize) {
		this.poolSize = poolSize;
	}

	public int getMaxPoolSize() {
		return poolSize;
	}

	public void shutdown() throws InterruptedException {
		log.info("shoutdown called");
		pool.shutdown();
		pool.awaitTermination(30, TimeUnit.SECONDS);
		pool.shutdownNow();
	  }
	/**
	 * Job : is a manageable unit of work. ie. 1 Job can have n number of threads all of which are executed in parallel.
	 * <br> when all the thread return back with answers only then you start next. i.e at one point of time 
	 * you should typically have just one job running.But the Job can have multiple threads running as JsonClients
	 * 
	 */
	public class Job {
		ArrayList<JsonClient> jobs = new ArrayList<JsonClient>();
		ArrayList<Future> responses = new ArrayList<Future>();

		public void addToJob(JsonClient job){
			jobs.add(job);
		}
		
		public void submitAllJobs(){
			for(JsonClient j : jobs){
				Future<JsonStatusBatchResponse> f = processClientRequest(j);
				responses.add(f);
			}
		}
		
		public List<JsonStatusBatchResponse> getReponseList(){
			ArrayList<JsonStatusBatchResponse> responseList = new ArrayList<JsonStatusBatchResponse>();
			Iterator<Future> it = responses.iterator();
			while(it.hasNext()){
				Future f = it.next();
				JsonStatusBatchResponse response;
				try {
					response = (JsonStatusBatchResponse)f.get();
					responseList.add(response);
				} catch (InterruptedException e) {
					log.error("Thread Interuppted - Exiting app" , e);
					throw new ApplicationException(e);
				} catch (ExecutionException e) {
					log.error("Thread ExecutionException - Exiting app" , e);
					throw new ApplicationException(e);
				}
			}
			return responseList;
		}

	
	}
	
}
